Dowiedz si臋, jak u偶ywa膰 AbortController w JavaScript, aby skutecznie anulowa膰 operacje asynchroniczne, takie jak 偶膮dania pobierania, timery i inne, zapewniaj膮c czystszy i wydajniejszy kod.
JavaScript AbortController: Opanowanie Anulowania Operacji Asynchronicznych
We wsp贸艂czesnym tworzeniu stron internetowych operacje asynchroniczne s膮 wszechobecne. Pobieranie danych z interfejs贸w API, ustawianie timer贸w i obs艂uga interakcji u偶ytkownika cz臋sto obejmuj膮 kod, kt贸ry dzia艂a niezale偶nie i potencjalnie przez d艂u偶szy czas. Istniej膮 jednak scenariusze, w kt贸rych nale偶y anulowa膰 te operacje przed ich zako艅czeniem. W艂a艣nie tutaj interfejs AbortController
w JavaScript przychodzi z pomoc膮. Zapewnia czysty i wydajny spos贸b sygnalizowania 偶膮da艅 anulowania do operacji DOM i innych zada艅 asynchronicznych.
Zrozumienie potrzeby anulowania
Zanim zag艂臋bimy si臋 w szczeg贸艂y techniczne, zrozumiejmy, dlaczego anulowanie operacji asynchronicznych jest wa偶ne. Rozwa偶my te typowe scenariusze:
- Nawigacja u偶ytkownika: U偶ytkownik inicjuje zapytanie wyszukiwania, uruchamiaj膮c 偶膮danie API. Je艣li szybko przejdzie do innej strony, zanim 偶膮danie si臋 zako艅czy, oryginalne 偶膮danie staje si臋 nieistotne i powinno zosta膰 anulowane, aby unikn膮膰 niepotrzebnego ruchu w sieci i potencjalnych skutk贸w ubocznych.
- Zarz膮dzanie limitem czasu: Ustawiasz limit czasu dla operacji asynchronicznej. Je艣li operacja zako艅czy si臋 przed up艂ywem limitu czasu, nale偶y anulowa膰 limit czasu, aby zapobiec zb臋dnemu wykonywaniu kodu.
- Odmontowywanie komponent贸w: W frameworkach front-endowych, takich jak React lub Vue.js, komponenty cz臋sto wykonuj膮 偶膮dania asynchroniczne. Gdy komponent si臋 odmontowuje, wszelkie trwaj膮ce 偶膮dania zwi膮zane z tym komponentem powinny zosta膰 anulowane, aby unikn膮膰 wyciek贸w pami臋ci i b艂臋d贸w spowodowanych aktualizacj膮 odmontowanych komponent贸w.
- Ograniczenia zasob贸w: W 艣rodowiskach o ograniczonych zasobach (np. urz膮dzenia mobilne, systemy wbudowane) anulowanie niepotrzebnych operacji mo偶e zwolni膰 cenne zasoby i poprawi膰 wydajno艣膰. Na przyk艂ad anulowanie pobierania du偶ego obrazu, je艣li u偶ytkownik przewinie obok tej sekcji strony.
Wprowadzenie do AbortController i AbortSignal
Interfejs AbortController
zosta艂 zaprojektowany w celu rozwi膮zania problemu anulowania operacji asynchronicznych. Sk艂ada si臋 z dw贸ch kluczowych komponent贸w:
- AbortController: Ten obiekt zarz膮dza sygna艂em anulowania. Ma jedn膮 metod臋,
abort()
, kt贸ra s艂u偶y do sygnalizowania 偶膮dania anulowania. - AbortSignal: Ten obiekt reprezentuje sygna艂, 偶e operacja powinna zosta膰 przerwana. Jest powi膮zany z
AbortController
i jest przekazywany do operacji asynchronicznej, kt贸ra musi by膰 anulowana.
Podstawowe u偶ycie: Anulowanie 偶膮da艅 pobierania
Zacznijmy od prostego przyk艂adu anulowania 偶膮dania fetch
:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Data:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});
// To cancel the fetch request:
controller.abort();
Wyja艣nienie:
- Tworzymy instancj臋
AbortController
. - Uzyskujemy powi膮zany
AbortSignal
zcontroller
. - Przekazujemy
signal
do opcjifetch
. - Je艣li musimy anulowa膰 偶膮danie, wywo艂ujemy
controller.abort()
. - W bloku
.catch()
sprawdzamy, czy b艂膮d toAbortError
. Je艣li tak, wiemy, 偶e 偶膮danie zosta艂o anulowane.
Obs艂uga AbortError
Po wywo艂aniu controller.abort()
, 偶膮danie fetch
zostanie odrzucone z AbortError
. Wa偶ne jest, aby odpowiednio obs艂u偶y膰 ten b艂膮d w swoim kodzie. Niezastosowanie si臋 do tego mo偶e prowadzi膰 do nieobs艂u偶onych odrzucze艅 obietnic i nieoczekiwanego zachowania.
Oto bardziej solidny przyk艂ad z obs艂ug膮 b艂臋d贸w:
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log('Data:', data);
return data;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
return null; // Or throw the error to be handled further up
} else {
console.error('Fetch error:', error);
throw error; // Re-throw the error to be handled further up
}
}
}
fetchData();
// To cancel the fetch request:
controller.abort();
Najlepsze praktyki dotycz膮ce obs艂ugi AbortError:
- Sprawd藕 nazw臋 b艂臋du: Zawsze sprawdzaj, czy
error.name === 'AbortError'
, aby upewni膰 si臋, 偶e obs艂ugujesz w艂a艣ciwy typ b艂臋du. - Zwr贸膰 warto艣膰 domy艣ln膮 lub ponownie rzu膰: W zale偶no艣ci od logiki aplikacji mo偶esz chcie膰 zwr贸ci膰 warto艣膰 domy艣ln膮 (np.
null
) lub ponownie rzuci膰 b艂膮d, aby obs艂u偶y膰 go wy偶ej w stosie wywo艂a艅. - Wyczy艣膰 zasoby: Je艣li operacja asynchroniczna przydzieli艂a jakiekolwiek zasoby (np. timery, listenery zdarze艅), wyczy艣膰 je w obs艂udze
AbortError
.
Anulowanie timer贸w z AbortSignal
AbortSignal
mo偶e by膰 r贸wnie偶 u偶ywany do anulowania timer贸w utworzonych za pomoc膮 setTimeout
lub setInterval
. Wymaga to nieco wi臋cej pracy r臋cznej, poniewa偶 wbudowane funkcje timera nie obs艂uguj膮 bezpo艣rednio AbortSignal
. Musisz utworzy膰 funkcj臋 niestandardow膮, kt贸ra nas艂uchuje sygna艂u przerwania i czy艣ci timer, gdy zostanie uruchomiony.
function cancellableTimeout(callback, delay, signal) {
let timeoutId;
const timeoutPromise = new Promise((resolve, reject) => {
timeoutId = setTimeout(() => {
resolve(callback());
}, delay);
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new Error('Timeout Aborted'));
});
});
return timeoutPromise;
}
const controller = new AbortController();
const signal = controller.signal;
cancellableTimeout(() => {
console.log('Timeout executed');
}, 2000, signal)
.then(() => console.log("Timeout finished successfully"))
.catch(err => console.log(err));
// To cancel the timeout:
controller.abort();
Wyja艣nienie:
- Funkcja
cancellableTimeout
przyjmuje wywo艂anie zwrotne, op贸藕nienie iAbortSignal
jako argumenty. - Ustawia
setTimeout
i przechowuje identyfikator limitu czasu. - Dodaje do
AbortSignal
detektor zdarze艅, kt贸ry nas艂uchuje zdarzeniaabort
. - Gdy zdarzenie
abort
zostanie uruchomione, detektor zdarze艅 czy艣ci limit czasu i odrzuca obietnic臋.
Anulowanie detektor贸w zdarze艅
Podobnie jak w przypadku timer贸w, mo偶esz u偶y膰 AbortSignal
do anulowania detektor贸w zdarze艅. Jest to szczeg贸lnie przydatne, gdy chcesz usun膮膰 detektory zdarze艅 powi膮zane z komponentem, kt贸ry jest odmontowywany.
const controller = new AbortController();
const signal = controller.signal;
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
}, { signal });
// To cancel the event listener:
controller.abort();
Wyja艣nienie:
- Przekazujemy
signal
jako opcj臋 do metodyaddEventListener
. - Gdy
controller.abort()
zostanie wywo艂ane, detektor zdarze艅 zostanie automatycznie usuni臋ty.
AbortController w komponentach React
W React mo偶esz u偶y膰 AbortController
do anulowania operacji asynchronicznych, gdy komponent si臋 odmontowuje. Jest to niezb臋dne, aby zapobiec wyciekom pami臋ci i b艂臋dom spowodowanym aktualizacj膮 odmontowanych komponent贸w. Oto przyk艂ad u偶ywaj膮cy haka useEffect
:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
setData(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
}
}
fetchData();
return () => {
controller.abort(); // Cancel the fetch request when the component unmounts
};
}, []); // Empty dependency array ensures this effect runs only once on mount
return (
{data ? (
Data: {JSON.stringify(data)}
) : (
Loading...
)}
);
}
export default MyComponent;
Wyja艣nienie:
- Tworzymy
AbortController
wewn膮trz hakauseEffect
. - Przekazujemy
signal
do 偶膮daniafetch
. - Zwracamy funkcj臋 czyszcz膮c膮 z haka
useEffect
. Ta funkcja zostanie wywo艂ana, gdy komponent si臋 odmontowuje. - Wewn膮trz funkcji czyszcz膮cej wywo艂ujemy
controller.abort()
, aby anulowa膰 偶膮danie pobierania.
Zaawansowane przypadki u偶ycia
艁a艅cuchowanie AbortSignal
Czasami mo偶esz chcie膰 po艂膮czy膰 wiele AbortSignal
razem. Na przyk艂ad mo偶esz mie膰 komponent nadrz臋dny, kt贸ry musi anulowa膰 operacje w swoich komponentach podrz臋dnych. Mo偶na to osi膮gn膮膰, tworz膮c nowy AbortController
i przekazuj膮c jego sygna艂 zar贸wno do komponent贸w nadrz臋dnych, jak i podrz臋dnych.
U偶ywanie AbortController z bibliotekami innych firm
Je艣li u偶ywasz biblioteki innej firmy, kt贸ra nie obs艂uguje bezpo艣rednio AbortSignal
, mo偶e by膰 konieczne dostosowanie kodu do wsp贸艂pracy z mechanizmem anulowania biblioteki. Mo偶e to obejmowa膰 zawijanie asynchronicznych funkcji biblioteki we w艂asne funkcje, kt贸re obs艂uguj膮 AbortSignal
.
Korzy艣ci z u偶ywania AbortController
- Poprawa wydajno艣ci: Anulowanie niepotrzebnych operacji mo偶e zmniejszy膰 ruch w sieci, wykorzystanie procesora i zu偶ycie pami臋ci, co prowadzi do poprawy wydajno艣ci, zw艂aszcza na urz膮dzeniach o ograniczonych zasobach.
- Czystszy kod:
AbortController
zapewnia znormalizowany i elegancki spos贸b zarz膮dzania anulowaniem, dzi臋ki czemu kod jest bardziej czytelny i 艂atwiejszy w utrzymaniu. - Zapobieganie wyciekom pami臋ci: Anulowanie operacji asynchronicznych powi膮zanych z odmontowanymi komponentami zapobiega wyciekom pami臋ci i b艂臋dom spowodowanym aktualizacj膮 odmontowanych komponent贸w.
- Lepsze wra偶enia u偶ytkownika: Anulowanie nieistotnych 偶膮da艅 mo偶e poprawi膰 wra偶enia u偶ytkownika, zapobiegaj膮c wy艣wietlaniu nieaktualnych informacji i zmniejszaj膮c postrzegane op贸藕nienia.
Zgodno艣膰 przegl膮darki
AbortController
jest szeroko obs艂ugiwany we wsp贸艂czesnych przegl膮darkach, w tym Chrome, Firefox, Safari i Edge. Mo偶esz sprawdzi膰 tabel臋 zgodno艣ci w dokumentach MDN Web Docs, aby uzyska膰 najnowsze informacje.
Polyfills
W przypadku starszych przegl膮darek, kt贸re natywnie nie obs艂uguj膮 AbortController
, mo偶na u偶y膰 polyfill. Polyfill to fragment kodu, kt贸ry zapewnia funkcjonalno艣膰 nowszej funkcji w starszych przegl膮darkach. Istnieje kilka dost臋pnych online polyfill贸w AbortController
.
Podsumowanie
Interfejs AbortController
jest pot臋偶nym narz臋dziem do zarz膮dzania operacjami asynchronicznymi w JavaScript. U偶ywaj膮c AbortController
, mo偶esz pisa膰 czystszy, wydajniejszy i bardziej niezawodny kod, kt贸ry elegancko obs艂uguje anulowanie. Niezale偶nie od tego, czy pobierasz dane z interfejs贸w API, ustawiasz timery, czy zarz膮dzasz detektorami zdarze艅, AbortController
mo偶e pom贸c w poprawie og贸lnej jako艣ci aplikacji internetowych.